/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GameController;

import Car.Car;
import GameView.RCCanvas;
import Point.Point;
import java.util.Random;
import java.util.Vector;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;

/**
 * Controller dari game
 * @author Christianto
 */
public class RCController 
        extends MIDlet
        implements CommandListener {
    
    private Random generator = new Random(2032L);
    private boolean started = false;
    private int MaxSpeed = 30;
    private int MaxLane = 9;
    private int rentang = 20;
    private int MaxCar = 10;
    private Vector ExistedCars;
    private Canvas RCView;
    private Display dsp;
    
    private Command CExit  = new Command("Exit", Command.EXIT, 5);
    
    public RCController()  {
        
        ExistedCars = new Vector(10);
        
        for (int i = 0; i < MaxLane; i++) {
           ExistedCars.addElement(new Car(new Point(i,MaxLane-i),(i+1)*3));
        }
    }
    
    public void startApp() {
        if (!started) {
            while(ExistedCars.size() > 0){
                for (int i=0;i<ExistedCars.size();++i) {
                    Car x = (Car)ExistedCars.elementAt(i);
                    x.Update(rentang);
                    if (generator.nextInt(10) < 3) {
                        x.SetVel((1+x.getVel()<MaxSpeed)?1+x.getVel():20);
                    }                    
                    ExistedCars.setElementAt(x, i);
                    if (x.getPos().getOrdinat()>22){
                        ExistedCars.removeElementAt(i);
                    }
                }
                
                int check = generator.nextInt(100);
                if (ExistedCars.size() <= MaxCar && check <= 55) {
                    AddCar();
                } 
                //Check whether there are collisions.
                CollisionChecker();
                
                //now try to ensure that in the next update
                //there wont be collisions.
                CollisionAvoiding();
                
                // Update Display
                RCView = new RCCanvas(ExistedCars);
                RCView.addCommand(CExit);
                RCView.setCommandListener(this);
                dsp = Display.getDisplay(this);
                dsp.setCurrent(RCView);      
        
                long t0,t1;
                t0=System.currentTimeMillis();
                do{
                    t1=System.currentTimeMillis();
                }
                while (t1-t0<50);
            }
            notifyDestroyed();
        } else {
        }
    }
    
    public void pauseApp() {
    }
    
    public void destroyApp(boolean unconditional) {
    }

    public void commandAction(Command c, Displayable d) {
        if (c==CExit){
            //System.out.println("DEBUG : EXIT");
            ExistedCars.removeAllElements();
            destroyApp(false);
            notifyDestroyed();
        }
    }
    
    /**
     * Procedure to checked if any of the cars are colliding
     * right now.
     * Delete (destroy) them whenever necessary.
     */
    private void CollisionChecker() {   
        boolean hapus[] = new boolean[ExistedCars.size()];
        for (int i = 0;i<ExistedCars.size();++i) hapus[i] = false;

        for (int i=0;i<ExistedCars.size();++i) {
            for (int j=0;j<i;++j) {
                Point c1 = ((Car)ExistedCars.elementAt(i)).getPos();
                Point c2 = ((Car)ExistedCars.elementAt(j)).getPos();
                hapus[i] = hapus[i] || collide(c1,c2);
                hapus[j] = hapus[j] || collide(c1,c2);
                
                //if (collide(c1,c2)) System.out.println(c1 + " -> " + c2);
            }
        }

        Vector survivor = new Vector();
        for (int i=0;i<ExistedCars.size();++i) {
            if (!hapus[i]) {
                survivor.addElement(ExistedCars.elementAt(i));
                //System.out.println("DEBUGHapus "+i);
            }
        }
        ExistedCars = survivor;
    }
    
    private boolean collide(Point a, Point b) {
        double akiri = Math.floor(a.getAbsis())-0.4;
        double abawah = Math.floor(a.getOrdinat());
        
        double bkiri = Math.floor(b.getAbsis())-0.4;
        double bbawah = Math.floor(b.getOrdinat());
        
        return (Math.max(akiri, bkiri)<=Math.min(akiri, bkiri)+0.8)&&
               (Math.max(abawah, bbawah)<=Math.min(abawah,bbawah)+1.0);
    }
    
    /**
     * procedure to avoid collision, by reducing the speed of the cars
     * whenever necessary.
     */
    private void CollisionAvoiding() {
        //boolean finish;        
        //do {
        //    finish = true;
            for (int i=0;i<ExistedCars.size();++i) {
                Car fProj = (Car)ExistedCars.elementAt(i);
                fProj.Update(rentang);
                for (int j=0;j<ExistedCars.size();++j) {
                    if (j == i) continue;
                    Point c1 = fProj.getPos();
                    Point c2 = ((Car)ExistedCars.elementAt(j)).getPos();
                    if ((Math.abs(c2.getAbsis()-c1.getAbsis())<1)
                            &&(c2.getOrdinat()-c1.getOrdinat()<3)
                            &&(c2.getOrdinat()-c1.getOrdinat()>0)) {
                        if(fProj.getVel()>10) fProj.SetVel(fProj.getVel()-5);
                        int belok = generator.nextInt(4);
                        if((belok==0)&&(fProj.getPos().getAbsis()==0)) belok=1;
                        if((belok==1)&&(fProj.getPos().getAbsis()==MaxLane-1)) belok=0;
                        if(belok==0) fProj.getPos().AddAbsis(-1); else
                        if(belok==1) fProj.getPos().AddAbsis(1); else
                        if(belok>2) fProj.SetVel(2);
                    }
                }
            }
        //} while (!finish);
    }
    
    /**
     * Procedure to add a new car to the screen.
     * Either add at the top or the bottom of the screen.
     */
    private void AddCar() {
        ExistedCars.addElement(new Car(new Point(generator.nextInt(MaxLane-1),-5),
                generator.nextInt(MaxSpeed-1)+1));
    }
}
